package www.dashu.com.dao.base;

import www.dashu.com.constant.Constants;
import lombok.Data;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@NoRepositoryBean
public interface BaseDao<T, ID> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T>
{

    @Data
    class MySpecification<T> implements Specification<T>
    {

        private Map<String, Object> queryParams;

        public MySpecification(Map<String, Object> queryParams)
        {
            this.queryParams = queryParams;
        }

        @Override
        public Specification<T> and(Specification<T> other)
        {
            return null;
        }

        @Override
        public Specification<T> or(Specification<T> other)
        {
            return null;
        }

        @Override
        public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder)
        {
            if(root.getJavaType().getSimpleName().toLowerCase().equals("cproduct")){
                query.multiselect(root.get("id"), root.get("name"));
            }
            if (null != queryParams) {
                List<Predicate> predicateList = new ArrayList<>();
                List<Predicate> andList = new ArrayList<>();
                queryParams.forEach((key, value) -> {
                    Path<Object> name = root.get(key);
                    if (!StringUtils.isEmpty(value)) {
                        if (value instanceof List) {
                            List<Object> list = (List<Object>) value;
                            if (key.equals("mid") || key.equals("status")) {
                                if (list.size() > 0) {
                                    List<Predicate> inOr = new ArrayList<>();
                                    for (int i = 0; i < list.size(); i++) {
                                        Predicate predicate = criteriaBuilder.equal(name.as(String.class), list.get(i));
                                        inOr.add(predicate);
                                    }
                                    Predicate[] inOr2 = new Predicate[inOr.size()];
                                    Predicate _predicate = criteriaBuilder.or(inOr.toArray(inOr2));
                                    andList.add(_predicate);
                                }
                            } else if (key.equals("createTime") || key.equals("updateTime")) {
                                Date date = (Date) list.get(0);
                                Date dateQ = new Date(date.getTime() - 300000); //5分钟之前
                                SimpleDateFormat sdf = new SimpleDateFormat(Constants.YYYY_MM_DD_HH_MM_SS);
                                String dateString = sdf.format(dateQ);
                                Predicate predicate = criteriaBuilder.lessThanOrEqualTo(name.as(String.class), dateString);
                                andList.add(predicate);
                            } else {
                                CriteriaBuilder.In<Object> in = criteriaBuilder.in(name.as(String.class));
                                list.forEach(item -> {
                                    in.value(item.toString());
                                });
                                predicateList.add(in);
                            }
                        } else {
                            Predicate predicate = criteriaBuilder.like(name.as(String.class), "%" + value + "%");
                            if(key.toLowerCase().contains("id") || key.toLowerCase().contains("status")){
                                predicate = criteriaBuilder.equal(name.as(String.class), value);
                            }
                            if (key.equals("callCount")) {
                                predicate = criteriaBuilder.lessThan(name.as(Integer.class), (Integer) value);
                                andList.add(predicate);
                            } else if (key.equals("mid") || key.equals("status")) {
                                predicate = criteriaBuilder.equal(name.as(String.class), String.valueOf(value));
                                andList.add(predicate);
                            } else {
//                                predicateList.add(predicate);
                                andList.add(predicate);
                            }
                        }

                    }
                });
                Predicate[] preOr = new Predicate[predicateList.size()];
                predicateList.toArray(preOr);
                Predicate predicateOr = criteriaBuilder.or(preOr);

                Predicate[] preAnd = new Predicate[andList.size()];
                andList.toArray(preAnd);
                Predicate predicateAnd = criteriaBuilder.and(preAnd);

                if (andList.size() > 0) {
                    if (predicateList.size() > 0) {
                        Predicate pWhere = criteriaBuilder.and(predicateOr, predicateAnd);
                        return query.where(new Predicate[]{pWhere}).getRestriction();
                    } else {
                        return query.where(new Predicate[]{predicateAnd}).getRestriction();
                    }
                } else {
                    if (predicateList.size() > 0) {
                        return query.where(new Predicate[]{predicateOr}).getRestriction();
                    } else {
                        return query.getRestriction();
                    }
                }

            }
            return query.getRestriction();
        }
    }
}
